function UData() {
	var _uKey = UKey.getInstance();
	var _data = _uKey.getData();
	
	var _selectedCharacters = [];
	var _matchedTaxa = [];
	var _unMatchedTaxa = [];
	var self = this;
	
	this.init = function() {
	}
	
	this.reset = function() {
		_selectedCharacters = [];
		_matchedTaxa = [];
		_unMatchedTaxa = [];
	};	

	this.selectCharacter = function(character) {
		if ( !character ) {
			return;
		}
			
		switch (character.type) {
		case UUtil.CHARACTER_TYPE_OrderedMultiState:
		case UUtil.CHARACTER_TYPE_UnorderedMultiState:
			if ( !character.selectedValues ) {
				alert("No seleted value for " + character.name);
				return;
			}
			break;
		default:
			if ( UUtil.isNull(character.enteredValue) ) {
				alert("No entered value value for " + character.name);
				return;
			}
			break;
		}
		
		var prevC = self.findCharacterByIdWithList(_selectedCharacters, character.id);
		if ( !prevC ) {
			_selectedCharacters.push(character);
		}
		doMatch();
	};
	
	function doMatch() {
		_matchedTaxa = [];
		_unMatchedTaxa = [];

		if ( _selectedCharacters && _selectedCharacters.length > 0 ) {
			doMatchList();
		} else {
			_matchedTaxa = [];
			_unMatchedTaxa = _data.taxa;
		}
		
		var selectedCharacterHash = [];
		for (var i=0; i<_selectedCharacters.length; i++) {
			var c = _selectedCharacters[i];
			selectedCharacterHash[c.id] = c;
		}

		unSelectedCharacterList = [];
		for (var i=0; i<_data.characters.length; i++) {
			var c = _data.characters[i];
			if ( selectedCharacterHash[c.id] ) {
				continue;
			}
			unSelectedCharacterList.push(c);
		}
		

		
		UKey.getInstance().updateUI(unSelectedCharacterList, _selectedCharacters, 
				_unMatchedTaxa, _matchedTaxa);		
	}
	
	function doMatchList() {
		var tLen = _data.taxa.length;
		var cLen = _selectedCharacters.length;		
		for (var i=0; i<tLen; i++) {
			var t = _data.taxa[i];
			var isMatch = true;
			for (var j=0; j<cLen; j++) {
				var c = _selectedCharacters[j];
				if ( !doMatchOne(c, t)) {
					isMatch = false;
					break;
				}
			}
			if ( isMatch ) {
				_matchedTaxa.push(t);
			} else {
				_unMatchedTaxa.push(t);
			}
		}
//		alert(_matchedTaxa.length + ' ' + _unMatchedTaxa.length );
	}
	function doMatchOne(character, taxon) {
		var attValue = self.findTaxonAttribute(taxon, character);
		if ( !attValue ) {
			return false;
		}
		switch (character.type) {
		case UUtil.CHARACTER_TYPE_OrderedMultiState:
		case UUtil.CHARACTER_TYPE_UnorderedMultiState:
			var values;			
			if ( UUtil.isArray(attValue) ) {
				values = attValue
			} else {
				values = [];
				values[0] = attValue;
			}
			if ( attValue.length < 0) {
				return false;
			}
			
			for (var i=0; i<character.selectedValues.length; i++) {
				var sV = character.selectedValues[i];
				for (var j=0; j<values.length; j++) {
					var aV = values[j];
					if ( sV == aV) {
						return true;
					}
				}
			}
			break;
		default:
			var sV = character.enteredValue;
			if ( UUtil.isArray(attValue) ) {
				for (var i=0; i<attValue.length; i++) {
					if ( sV == attValue[i]) {
						return true;
					}
				}
			} else if ( !UUtil.isUndefined(attValue.min) && !UUtil.isUndefined(attValue.max) ) {
				if ( sV >= attValue.min && sV <= attValue.max) {
					return true;
				}
			} else {
				if ( UUtil.isString(attValue) ) {
					if ( sV.indexOf(attValue+'') > -1 ) {
						return true;
					}
				} else {
					if ( sV == attValue ) {
						return true;
					}
				}
			}
			break;
		}
		return false;
	}
	
	this.removeCharacter = function(id) {
		if ( !_selectedCharacters || _selectedCharacters.length < 1 ) {
			return;
		}
		var newList = [];
		for (var i=0; i<_selectedCharacters.length; i++) {
			var c = _selectedCharacters[i];
			if ( c.id == id ) {
				continue;
			}
			newList.push(c);
		}
		if ( newList.length != _selectedCharacters.length ) {
			_selectedCharacters = newList;
			doMatch();
		}
	}
	
	this.findTaxonAttribute = function(taxon, character) {
		if (  UUtil.isNull(character.data) ) {
			return;
		}
		
		var atts = character.data;
		
		if (!atts || atts.length < 1 ) {
			return null;
		}
		
		var index = taxon.id - 1;
		var value = null;
		if ( index < atts.length ) {
			value = atts[index];
		}
		
		if ( !value ) {
			return value;
		}
		
		if ( UUtil.isArray(value) ) {
			return value;
		}
		if ( UUtil.isString(value) ) {
			if ( value.indexOf("-") > 0 ) {
				var words = value.split("-");
				if ( words && words.length > 1 ) {
					var obj = new Object();
					obj.min = UUtil.parseFloat(words[0]);
					obj.max = UUtil.parseFloat(words[1]);
					return obj;
				}
			}
		}
		return value;
	
		
		
/*		
		var atts = taxon.a;
		if ( atts == null || atts.length < 1 ) {
			return null;
		}
		
		var len = atts.length;
		for (var i=0; i<len; i++) {
			var a = atts[i];
			if ( a.c == characterId ) {
				return a;
			}
		}	
*/		
	};	
	
	this.findCharacterById = function(id) {
		return self.findCharacterByIdWithList(_data.characters, id);
	};
	
	this.findCharacterByIdWithList = function(list, id) {
		var len = list.length;
		for (var i=0; i<len; i++) {
			var c = list[i];
			if ( c.id == id ) {
				return c;
			}
		}
	};	
	
	this.findTaxaById = function(id) {
		return self.findTaxaByIdWithList(_data.taxa, id);
	};
	
	this.findTaxaByIdWithList = function(list, id) {
		var len = list.length;
		for (var i=0; i<len; i++) {
			var c = list[i];
			if ( c.id == id ) {
				return c;
			}
		}
	};		
}

UData.getInstance = function() {
	if ( UData._instance == null ) {
		UData._instance = new UData();
		UData._instance.init();
		UData._instance.reset();
	}
	return UData._instance;
};
